package server.loader;

import com.Ostermiller.util.Base64;
import constans.ArcConstans;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import database.DatabaseOperationsCapsules;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.sql.SQLException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import constans.CapsuleConstans;
import constans.ErrorConstants;
import constans.SizeConstans;
import security.CipherFile;
import security.CipherFileAES;
import security.MessageDigestSHA1;
import security.Signature;
import security.SignatureSHA1;
import database.ConnectionDB;
import database.DatabaseMysql;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.util.Properties;
import utils.LogUtils;

public class CapsuleLoader {

    
    private Logger logger;
    private Properties properties;
    private Signature signature;
    private CipherFile cipherFile;
    private MessageDigestSHA1 md;
    private Scanner inputKeyboard;
    private DatabaseOperationsCapsules dbOpCapsules;

    
    public CapsuleLoader(String nameConfigurationFile) {
       try {
            properties = new Properties();
            properties.load(new FileReader(nameConfigurationFile));
        } catch (IOException ex) {
            logger.log(Level.SEVERE, "Error code ("+ErrorConstants.ERROR_CONFIGURATION_FILE+"): "+ex.getMessage());
            System.exit(ErrorConstants.ERROR_CONFIGURATION_FILE);
        }
    }


	public void run(){

		System.out.println("--CapsuleLoader--");
		System.out.println();

        try {
            logger = LogUtils.getLogger("CapsuleLoader", "capsuleLoader.log");
        } catch (IOException ex) {
            //TODO
            System.exit(1);
        }

        dbOpCapsules = getDatabaseOperationsCapsules();

        signature = getSignature();
            
        cipherFile = getCipherFilej();
      
        md = getMessageDigestSHA1();

        inputKeyboard = new Scanner(System.in);
        
    	int option;

        while(true){

			try{

				System.out.println();
				System.out.println("1 - Load ARC files into Capsules");
				System.out.println("0 - Exit");
				System.out.println("Option: ");

				option =  Integer.parseInt(inputKeyboard.next());

				if(option == 1)
					menuLoadCapsules(inputKeyboard);
				else if(option==0)		
					break;
				else
					System.out.println("Invalid option");

			} catch (NumberFormatException ex) {
				System.out.println("Invalid option");
			}  catch (SQLException ex) {
           	    logger.log(Level.SEVERE, "Error code("+ErrorConstants.ERROR_DATABASE+"): "+ex.getMessage());
                System.exit(ErrorConstants.ERROR_DATABASE);
			}
            
			System.out.println();
		}

        closeResouces();
        
		System.out.println("Exit");		
	}


	//private
	private void menuLoadCapsules(Scanner scanner)
            throws SQLException{

		System.out.println("Insert arc folder:  ");
	    File arcFolder = new File( scanner.next());

		File capsuleFolder = getFolderCapsule();

		if(capsuleFolder.exists()){
			if(arcFolder.exists()){

		     File []  listArcFiles = arcFolder.listFiles( new FilenameFilter(){
                public boolean accept(File file, String name) {
                    return name.endsWith(ArcConstans.ARC_EXTENSION);
                }
            });

              if(listArcFiles!=null){
					for(int i = 0 ; i < listArcFiles.length ; i++){
						try {
							if(loadCapsule(listArcFiles[i], capsuleFolder)){
								System.out.println("capsule ("+listArcFiles[i].getName()+") created");
							}else{
								System.out.println("capsule ("+listArcFiles[i].getName()+") already exists");
							}						
						}
						catch (IOException e) {
							System.out.println("capsule ("+listArcFiles[i].getName()+") problems to load");
						}
					}
				}else{
					System.out.println("The folder of arcs is empty");
				}
			}else{
				System.out.println("The folder of arcs does not exist");
			}
		}else{
			System.out.println("The folder of capsules does not exist");
		}
	}


	private DatabaseOperationsCapsules getDatabaseOperationsCapsules(){

		ConnectionDB connectionDB = null;
        DatabaseOperationsCapsules dbOperationsCapsules = null;
        try {

            connectionDB = new DatabaseMysql(properties.getProperty("DatabaseHost"),
                properties.getProperty("DatabaseUser"), properties.getProperty("DatabasePass"),
                properties.getProperty("DatabaseName")).getConnection();

            dbOperationsCapsules = new DatabaseOperationsCapsules(connectionDB);
           
        } catch (SQLException ex) {
            if(connectionDB!=null)
                try {
                connectionDB.close();
                } catch (SQLException e) {}

            logger.log(Level.SEVERE, "Error code ("+ErrorConstants.ERROR_DATABASE+"): "+ex.getMessage());
            System.exit(ErrorConstants.ERROR_DATABASE);
        }

        return dbOperationsCapsules;
	}


    private MessageDigestSHA1 getMessageDigestSHA1(){

        MessageDigestSHA1 mdsha = null;

        try {
            mdsha = new MessageDigestSHA1();
        } catch (GeneralSecurityException ex) {
                Logger.getLogger(CapsuleLoader.class.getName()).log(Level.SEVERE, null, ex);
        }

        return mdsha;
    }

    
	private Signature getSignature(){

        Signature s =null;
        try {
            s = new SignatureSHA1(properties.getProperty("PassSignature").getBytes("UTF-8"));
        } catch (GeneralSecurityException ex) {
            logger.log(Level.SEVERE, "Error code("+ErrorConstants.ERROR_SIGNATURE_PASSWORD+"): "+ex.getMessage());
            System.exit(ErrorConstants.ERROR_SIGNATURE_PASSWORD);
        } catch (UnsupportedEncodingException ex) {
            //TODO
            System.exit(1);
        }

        return s;
	}


	private CipherFile getCipherFilej(){

        CipherFile cf = null;
        try {
                cf = new CipherFileAES(properties.getProperty("PassCipher").getBytes("UTF-8"));
        } catch (GeneralSecurityException ex) {
           logger.log(Level.SEVERE, "Error code("+ErrorConstants.ERROR_CIPHER_PASSWORD+"): "+ex.getMessage());
           System.exit(ErrorConstants.ERROR_CIPHER_PASSWORD);
        } catch (UnsupportedEncodingException ex) {
           //TODO
            System.exit(1);
        }

        return cf;
	}

     private File getFolderCapsule(){
        return new File(properties.getProperty("FolderCapsule"));
    }


	private void closeResouces(){

		try {
			if(dbOpCapsules!=null)		
				dbOpCapsules.close();
		} catch (SQLException e) {}

		if(inputKeyboard!=null)
			inputKeyboard.close();	
	}


	private boolean loadCapsule(File arcFile, File folderCapsule)
            throws IOException, SQLException{

		String nameCapsule = arcFile.getName() +CapsuleConstans.CAPSULE_EXTENSION;

		boolean existsCapsule = dbOpCapsules.existsCapsule(nameCapsule);

		if(!existsCapsule){

			byte [] signatureArc = signature.getSignature(arcFile);

			File temporary = File.createTempFile(arcFile.getName(),CapsuleConstans.CAPSULE_TEMPORARY_EXTENSION, folderCapsule);

			createCapsuleTemporary(arcFile, temporary, signatureArc);

			File capsule = new File(folderCapsule,nameCapsule);

			cipherFile.encrypt(temporary,capsule);

			byte [] hashCapsule = md.digest(capsule);

			dbOpCapsules.insertCapsule(nameCapsule, capsule.length(), Base64.encodeToString(hashCapsule));

			temporary.delete();

			return true;

		}else{
			return false;
		}
	}


	private void createCapsuleTemporary(File arc, File capsule, byte [] signatureArc)
            throws FileNotFoundException,IOException{

		FileInputStream fileInput  = null;
		FileOutputStream fileOutput = null;

		try {
            
			fileInput  = new FileInputStream(arc);
			fileOutput = new FileOutputStream(capsule);

			byte[] buffer = new byte[(int)SizeConstans.KByte];
			int numRead = 0;

			while ((numRead = fileInput.read(buffer)) >=0)
				fileOutput.write(buffer, 0, numRead);
			fileOutput.write(signatureArc);
			fileOutput.flush();

			fileOutput.close();
 		    fileInput.close();

		} catch (FileNotFoundException e) {
			try {
				if(fileInput!=null){
					fileInput.close();
					fileInput = null;
				}
			} catch (IOException e1){}
			try {
				if(fileOutput!=null){
					fileOutput.close();
					fileOutput = null;
				}
			} catch (IOException e1){}
			throw new FileNotFoundException(e.getMessage());
		} catch (IOException e) {
			try {
				if(fileInput!=null){
					fileInput.close();
					fileInput = null;
				}
			} catch (IOException e1){}
			try {
				if(fileOutput!=null){
					fileOutput.close();
					fileOutput = null;
				}
			} catch (IOException e1){}
			throw new IOException(e);
		}
	}


	public static void main(String[] args) {
        if (args.length != 1) {
            System.out.println("Sintaxe: java CapsuleLoader <configuration filename>");
        } else {
           new CapsuleLoader(args[0]).run();
        }
	}


}
